package com.oh.core.server.handler;

import com.oh.core.common.base.MessageService;
import com.oh.core.common.cache.ChannelStore;
import com.oh.core.common.constant.CommandEnum;
import com.oh.core.common.constant.ConfigConst;
import com.oh.core.common.utils.MessageUtils;
import com.oh.core.common.utils.NettyAttrUtils;
import com.oh.core.common.utils.ServiceRouteFactory;
import com.oh.core.entity.MessageEntity;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.net.InetSocketAddress;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Optional;

@ChannelHandler.Sharable
@Component
public class OhServerHandler extends SimpleChannelInboundHandler<MessageEntity> {

    private final Logger log = LoggerFactory.getLogger(OhServerHandler.class);

    private final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");

    // 是否开启鉴权
    @Value("${oh.security.isOpen:true}")
    private Boolean isOpen;

    @Override
    protected void channelRead0(ChannelHandlerContext channelHandlerContext, MessageEntity messageEntity) throws Exception {
        Optional<MessageService> optional = ServiceRouteFactory.getService(messageEntity.getCommand());
        Channel channel = channelHandlerContext.channel();
        // 系统返回消息
        String backMsg = "OK";
        // 是否发送消息
        boolean sendBack = false;
        if(optional.isPresent()){
            // 鉴权判断
            if(isOpen){
                int magic = messageEntity.getHeadInfo().getMagic();
                if(magic != ConfigConst.MAGIC_NUMBER_CLIENT){
                    backMsg = "校验码/魔数错误！";
                    this.sendBackMsg(channel, backMsg);
                    return;
                }
                Byte command = messageEntity.getCommand();
                if(!NettyAttrUtils.hasClientId(channel) && command != CommandEnum.LOGIN_REQUEST.getCommand()){
                    backMsg = "非法请求，请先登录！";
                    this.sendBackMsg(channel, backMsg);
                    return;
                }
            }
            MessageService messageService = optional.get();
            // 校验
            int i = messageService.handle(channelHandlerContext, messageEntity);
            // 业务处理
            if(i < 0){
                backMsg = "业务数据校验异常【{" + i + "}】";
                log.warn(backMsg);
                sendBack = true;
            }
        }else{
            backMsg = "未获取到相关服务，指令【" + messageEntity.getCommand() + "】无效！ " + sdf.format(new Date());
            log.error(backMsg);
            sendBack = true;
        }
        if(sendBack){
            this.sendBackMsg(channel, backMsg);
        }
    }

    @Override
    public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
        Channel channel = ctx.channel();
        String channelId = channel.id().asLongText();
        ChannelStore.setChannel(channelId, channel);

        InetSocketAddress ipSocket = (InetSocketAddress)channel.remoteAddress();
        String clientIp = ipSocket.getAddress().getHostAddress();
        int port = ipSocket.getPort();
        log.info("【连接】客户端链接:IP地址:{}, 端口:{}，客户端ID {}，链接数{}", clientIp, port, channel.id().asLongText(), ChannelStore.getAllChannel().size());
    }

    @Override
    public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
        log.info("客户端断开链接");
        String channelId = ctx.channel().id().asLongText();
        ChannelStore.removeChannel(channelId);
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        String msg = this.getClass().getName() + "发生异常:"+ cause.getMessage();
        log.error(msg);
//        cause.printStackTrace();
        Channel channel = ctx.channel();
        String channelId = channel.id().asLongText();
        ChannelStore.removeChannel(channelId);
        this.sendBackMsg(channel, "服务端发生异常，请联系管理员！");
        channel.close();
    }

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
//        log.info("执行了channelActive，channelActive = " + ctx.name());
        ctx.fireChannelActive();
    }

    /**
     * channel连接状态断开后触发
     * @param ctx
     * @throws Exception
     */
    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        Channel channel = ctx.channel();
        InetSocketAddress ipSocket = (InetSocketAddress)channel.remoteAddress();
        String clientIp = ipSocket.getAddress().getHostAddress();
        int port = ipSocket.getPort();
        String msg = sdf.format(new Date()) +" 用户：" + channel.id().asLongText() + " IP端口：" + clientIp + ":" + port +" 下线 ";
        log.info(msg);
        // 通知所有客户端
        MessageUtils.sendMsgToAll(msg.getBytes());
    }

    /**
     * 发送消息
     * @param channel 通道
     * @param backMsg 返回消息
     */
    private void sendBackMsg(Channel channel, String backMsg){
        MessageUtils.channelMsg(channel, new MessageEntity(CommandEnum.MESSAGE_REQUEST.getCommand(), backMsg.getBytes()));
    }
}
